package class03;

import java.util.LinkedList;

// 判断给定的头节点是否为完全二叉树
public class Code09_IsCBT {

    public static class Node {
        public int value;
        public Node left;
        public Node right;

        public Node(int data) {
            this.value = data;
        }
    }


    public static boolean isCBT1(Node head) {
        if (head == null) {
            return true;
        }


        // 申请一个队列
        LinkedList<Node> list = new LinkedList<>();
        list.add(head);

        // 左右节点初始化
        Node left;
        Node right;
        // 是否遇到过不完整的叶子节点
        boolean leaf = false;

        while (!list.isEmpty()) {
            Node cur = list.poll();
            if (null == cur) {
                return true;
            }

            left = cur.left;
            right = cur.right;

            if (
                // 如果遇到了不双全的节点之后，又发现当前节点不是叶节点
                    (leaf && (left != null || right != null))
                            ||
                            (left == null && right != null)

            ) {
                return false;
            }

            if (null != left) {
                list.add(left);
            }
            if (null != right) {
                list.add(right);
            }

            if (left == null || right == null) {
                leaf = true;
            }


        }
        return true;

    }


    public static class Info {
        boolean isBST;
        boolean isFull;
        int height;

        Info(boolean b, boolean f, int h) {
            this.isBST = b;
            this.isFull = f;
            this.height = h;
        }

    }

    public static boolean isCBT2(Node head) {
        return process2(head).isBST;
    }

    static Info process2(Node head) {
        if (null == head) {

            return new Info(true, true, 0);
        }
        Info leftInfo = process2(head.left);
        Info rightInfo = process2(head.right);
        boolean isBST;
        boolean isFull = leftInfo.isFull && rightInfo.isFull && leftInfo.height == rightInfo.height;
        int height = Math.max(leftInfo.height, rightInfo.height) + 1;

        isBST = isFull;

        if (leftInfo.isBST && rightInfo.isFull && leftInfo.height == rightInfo.height + 1) {
            isBST = true;
        }
        if (leftInfo.isFull && rightInfo.isFull && leftInfo.height == rightInfo.height + 1) {
            isBST = true;
        }
        if (leftInfo.isFull && rightInfo.isBST && leftInfo.height == rightInfo.height) {
            isBST = true;
        }
        return new Info(isBST, isFull, height);
    }

    public static boolean isCompleteTree1(Node head) {
        if (head == null) {
            return true;
        }
        LinkedList<Node> queue = new LinkedList<>();
        // 是否遇到过左右两个孩子不双全的节点
        boolean leaf = false;
        Node l = null;
        Node r = null;
        queue.add(head);
        while (!queue.isEmpty()) {
            head = queue.pop();
            l = head.left;
            r = head.right;
            if (
                // 如果遇到了不双全的节点之后，又发现当前节点不是叶节点
                    (leaf && (l != null || r != null))
                            ||
                            (l == null && r != null)

            ) {
                return false;
            }
            if (l != null) {
                queue.add(l);
            }
            if (r != null) {
                queue.add(r);
            }
            if (l == null || r == null) {
                leaf = true;
            }
        }
        return true;
    }


    // for test
    public static Node generateRandomBST(int maxLevel, int maxValue) {
        return generate(1, maxLevel, maxValue);
    }

    // for test
    public static Node generate(int level, int maxLevel, int maxValue) {
        if (level > maxLevel || Math.random() < 0.5) {
            return null;
        }
        Node head = new Node((int) (Math.random() * maxValue));
        head.left = generate(level + 1, maxLevel, maxValue);
        head.right = generate(level + 1, maxLevel, maxValue);
        return head;
    }


    public static void main(String[] args) {
        int maxLevel = 5;
        int maxValue = 100;
        int testTimes = 1000000;
        for (int i = 0; i < testTimes; i++) {
            Node head = generateRandomBST(maxLevel, maxValue);
            if (isCBT1(head) != isCBT2(head)){
                System.out.println("Oops!");
            }
        }
        System.out.println("finish!");
    }
}
